/**
 * 获取 knowledge 目录的结构。如果目录不存在或缺少 entry 目录，会尝试创建 entry 目录后再次获取。
 *
 * @returns {Promise<Array>} 包含 knowledge 目录结构的数组
 */
async function getKnowledgeDirectoryStructure() {
	/** 检查给定的项目列表中是否包含名为 'entry' 的目录 */
	function hasEntryDirectory(items) {
		return items.some(item => item.name === 'entry' && item.isDir);
	};
	// 尝试获取 knowledge 目录结构
	try {
		/** 尝试获取 knowledge 目录结构 */
		const response = await fetch('/files/knowledge');
		// 检查响应是否成功，失败则抛出错误
		if (!response.ok) throw new Error('获取knowledge目录结构失败');
		/** 解析响应数据为 JSON */
		const directoryStructure = await response.json();
		// 检查目录结构是否缺少 entry 目录，是则抛出错误
		if (!hasEntryDirectory(directoryStructure)) throw new Error('缺少entry目录');
		// 返回获取到的目录结构
		return directoryStructure;
	}
	catch (error) {
		/** 生成临时文件的名称，用于创建 entry 目录 */
		const tempFileName = toBtoaString("knowledge/entry/.temp");
		/** 发送 POST 请求创建临时文件，以此触发 entry 目录的创建 */
		const initResponse = await fetch('/save',
			{
				method: 'POST',
				headers: {
					'Content-Type': 'text/plain',
					'X-File-Name': tempFileName,
					'X-Overwrite': 'true'
				},
				body: ''
			}
		);
		// 删除临时文件
		await fetch('/delete/knowledge/entry/.temp', { method: 'DELETE' });
		// 检查创建操作是否成功，失败则抛出错误
		if (!initResponse.ok) throw new Error('创建entry目录失败');
		/** 再次尝试获取 knowledge 目录结构 */
		const updatedResponse = await fetch('/files/knowledge');
		// 检查响应是否成功，失败则抛出错误
		if (!updatedResponse.ok) throw new Error('获取knowledge目录结构失败');
		/** 解析响应数据为 JSON */
		const directoryStructure = await updatedResponse.json();
		// 检查目录结构是否为空或缺少 entry 目录，是则抛出错误
		if (directoryStructure.length === 0 || !hasEntryDirectory(directoryStructure)) throw new Error('缺少entry目录');
		// 返回获取到的目录结构
		return directoryStructure;
	}
};

/**
 * 获取 entry 目录下的文件列表
 *
 * @returns {Promise<Array>} 包含 entry 目录下文件列表的数组，请求失败时返回空数组
 */
async function getEntryDirectoryFiles() {
	/** 发送请求获取 knowledge 目录下 entry 子目录的文件列表 */
	const response = await fetch('/files/knowledge/entry');
	// 检查响应是否成功，若失败则直接返回空数组
	if (!response.ok) return [];
	/** 解析响应数据为 JSON */
	const files = await response.json();
	// 若解析结果为空，则返回空数组，否则返回解析后的文件列表
	return files || [];
}

/**
 * 读取文件内容并按指定大小进行分块
 *
 * @param {Object} file - 要读取和分块的文件对象，需包含 name 属性
 *
 * @param {number} maxChunkSize - 每个分块的最大大小
 *
 * @returns {Array} 包含文件分块信息的数组，每个元素包含 chunkIndex 和 content 属性
 */
async function readAndChunkFile(file, maxChunkSize) {
	/** 用于存储文件分块信息的数组 */
	const fileChunks = [];
	// 渲染消息到简单知识面板，提示正在读取文件
	tracelessRenderMessage(`读取文件: /read/knowledge/entry/${file.name}`, simpleKnowledgePanel);
	/** 发送 GET 请求读取指定文件的内容 */
	const response = await fetch(`/read/knowledge/entry/${file.name}`);
	// 检查请求是否成功，若失败则打印错误信息并返回空数组
	if (!response.ok) {
		showSystemMessage(response.status, 'error');
		return fileChunks;
	}
	/** 获取响应的文本内容 */
	const content = await response.text();
	/** 将文件内容按指定大小进行分块 */
	const chunks = splitTextToStrings(content, maxChunkSize);
	// 遍历分块结果，将每个分块的索引和内容添加到文件分块数组中
	chunks.forEach((chunk, index) => fileChunks.push({ chunkIndex: index, content: chunk }));
	// 渲染消息到简单知识面板，提示文件分块完成及分块数量
	tracelessRenderMessage(`文件 ${file.name} 被分割成 ${chunks.length} 块`, simpleKnowledgePanel);
	// 返回包含文件分块信息的数组
	return fileChunks;
}

/**
 * 清理 entry 目录下的非目录文件
 *
 * @param {Array} paths - 包含文件或目录信息的数组，每个元素需包含 name 和 isDir 属性
 */
async function clearEntryDirectoryFiles(paths) {
	// 遍历传入的路径列表
	for (const path of paths) {
		// 如果当前路径是目录，则跳过本次循环
		if (path.isDir) continue;
		/** 发送 DELETE 请求删除非目录文件 */
		const response = await fetch(`/delete/knowledge/entry/${path.name}`, { method: 'DELETE' });
		// 若请求失败，显示系统错误消息
		if (!response.ok) showSystemMessage(response.status, 'error');
	}
}